/*
 * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved.
 * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 */

package javax.swing.plaf.synth;

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.plaf.*;
import javax.swing.plaf.basic.BasicInternalFrameTitlePane;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyVetoException;
import sun.swing.SwingUtilities2;

/**
 * The class that manages a synth title bar
 *
 * @author David Kloba
 * @author Joshua Outwater
 * @author Steve Wilson
 */
class SynthInternalFrameTitlePane extends BasicInternalFrameTitlePane
    implements SynthUI, PropertyChangeListener {

  protected JPopupMenu systemPopupMenu;
  protected JButton menuButton;

  private SynthStyle style;
  private int titleSpacing;
  private int buttonSpacing;
  // Alignment for the title, one of SwingConstants.(LEADING|TRAILING|CENTER)
  private int titleAlignment;

  public SynthInternalFrameTitlePane(JInternalFrame f) {
    super(f);
  }

  public String getUIClassID() {
    return "InternalFrameTitlePaneUI";
  }

  public SynthContext getContext(JComponent c) {
    return getContext(c, getComponentState(c));
  }

  public SynthContext getContext(JComponent c, int state) {
    return SynthContext.getContext(c, style, state);
  }

  private Region getRegion(JComponent c) {
    return SynthLookAndFeel.getRegion(c);
  }

  private int getComponentState(JComponent c) {
    if (frame != null) {
      if (frame.isSelected()) {
        return SELECTED;
      }
    }
    return SynthLookAndFeel.getComponentState(c);
  }

  protected void addSubComponents() {
    menuButton.setName("InternalFrameTitlePane.menuButton");
    iconButton.setName("InternalFrameTitlePane.iconifyButton");
    maxButton.setName("InternalFrameTitlePane.maximizeButton");
    closeButton.setName("InternalFrameTitlePane.closeButton");

    add(menuButton);
    add(iconButton);
    add(maxButton);
    add(closeButton);
  }

  protected void installListeners() {
    super.installListeners();
    frame.addPropertyChangeListener(this);
    addPropertyChangeListener(this);
  }

  protected void uninstallListeners() {
    frame.removePropertyChangeListener(this);
    removePropertyChangeListener(this);
    super.uninstallListeners();
  }

  private void updateStyle(JComponent c) {
    SynthContext context = getContext(this, ENABLED);
    SynthStyle oldStyle = style;
    style = SynthLookAndFeel.updateStyle(context, this);
    if (style != oldStyle) {
      maxIcon =
          style.getIcon(context, "InternalFrameTitlePane.maximizeIcon");
      minIcon =
          style.getIcon(context, "InternalFrameTitlePane.minimizeIcon");
      iconIcon =
          style.getIcon(context, "InternalFrameTitlePane.iconifyIcon");
      closeIcon =
          style.getIcon(context, "InternalFrameTitlePane.closeIcon");
      titleSpacing = style.getInt(context,
          "InternalFrameTitlePane.titleSpacing", 2);
      buttonSpacing = style.getInt(context,
          "InternalFrameTitlePane.buttonSpacing", 2);
      String alignString = (String) style.get(context,
          "InternalFrameTitlePane.titleAlignment");
      titleAlignment = SwingConstants.LEADING;
      if (alignString != null) {
        alignString = alignString.toUpperCase();
        if (alignString.equals("TRAILING")) {
          titleAlignment = SwingConstants.TRAILING;
        } else if (alignString.equals("CENTER")) {
          titleAlignment = SwingConstants.CENTER;
        }
      }
    }
    context.dispose();
  }

  protected void installDefaults() {
    super.installDefaults();
    updateStyle(this);
  }

  protected void uninstallDefaults() {
    SynthContext context = getContext(this, ENABLED);
    style.uninstallDefaults(context);
    context.dispose();
    style = null;
    JInternalFrame.JDesktopIcon di = frame.getDesktopIcon();
    if (di != null && di.getComponentPopupMenu() == systemPopupMenu) {
      // Release link to systemMenu from the JInternalFrame
      di.setComponentPopupMenu(null);
    }
    super.uninstallDefaults();
  }

  private static class JPopupMenuUIResource extends JPopupMenu implements
      UIResource {

  }

  protected void assembleSystemMenu() {
    systemPopupMenu = new JPopupMenuUIResource();
    addSystemMenuItems(systemPopupMenu);
    enableActions();
    menuButton = createNoFocusButton();
    updateMenuIcon();
    menuButton.addMouseListener(new MouseAdapter() {
      public void mousePressed(MouseEvent e) {
        try {
          frame.setSelected(true);
        } catch (PropertyVetoException pve) {
        }
        showSystemMenu();
      }
    });
    JPopupMenu p = frame.getComponentPopupMenu();
    if (p == null || p instanceof UIResource) {
      frame.setComponentPopupMenu(systemPopupMenu);
    }
    if (frame.getDesktopIcon() != null) {
      p = frame.getDesktopIcon().getComponentPopupMenu();
      if (p == null || p instanceof UIResource) {
        frame.getDesktopIcon().setComponentPopupMenu(systemPopupMenu);
      }
    }
    setInheritsPopupMenu(true);
  }

  protected void addSystemMenuItems(JPopupMenu menu) {
    JMenuItem mi = menu.add(restoreAction);
    mi.setMnemonic(getButtonMnemonic("restore"));
    mi = menu.add(moveAction);
    mi.setMnemonic(getButtonMnemonic("move"));
    mi = menu.add(sizeAction);
    mi.setMnemonic(getButtonMnemonic("size"));
    mi = menu.add(iconifyAction);
    mi.setMnemonic(getButtonMnemonic("minimize"));
    mi = menu.add(maximizeAction);
    mi.setMnemonic(getButtonMnemonic("maximize"));
    menu.add(new JSeparator());
    mi = menu.add(closeAction);
    mi.setMnemonic(getButtonMnemonic("close"));
  }

  private static int getButtonMnemonic(String button) {
    try {
      return Integer.parseInt(UIManager.getString(
          "InternalFrameTitlePane." + button + "Button.mnemonic"));
    } catch (NumberFormatException e) {
      return -1;
    }
  }

  protected void showSystemMenu() {
    Insets insets = frame.getInsets();
    if (!frame.isIcon()) {
      systemPopupMenu.show(frame, menuButton.getX(), getY() + getHeight());
    } else {
      systemPopupMenu.show(menuButton,
          getX() - insets.left - insets.right,
          getY() - systemPopupMenu.getPreferredSize().height -
              insets.bottom - insets.top);
    }
  }

  // SynthInternalFrameTitlePane has no UI, we'll invoke paint on it.
  public void paintComponent(Graphics g) {
    SynthContext context = getContext(this);
    SynthLookAndFeel.update(context, g);
    context.getPainter().paintInternalFrameTitlePaneBackground(context,
        g, 0, 0, getWidth(), getHeight());
    paint(context, g);
    context.dispose();
  }

  protected void paint(SynthContext context, Graphics g) {
    String title = frame.getTitle();

    if (title != null) {
      SynthStyle style = context.getStyle();

      g.setColor(style.getColor(context, ColorType.TEXT_FOREGROUND));
      g.setFont(style.getFont(context));

      // Center text vertically.
      FontMetrics fm = SwingUtilities2.getFontMetrics(frame, g);
      int baseline = (getHeight() + fm.getAscent() - fm.getLeading() -
          fm.getDescent()) / 2;
      JButton lastButton = null;
      if (frame.isIconifiable()) {
        lastButton = iconButton;
      } else if (frame.isMaximizable()) {
        lastButton = maxButton;
      } else if (frame.isClosable()) {
        lastButton = closeButton;
      }
      int maxX;
      int minX;
      boolean ltr = SynthLookAndFeel.isLeftToRight(frame);
      int titleAlignment = this.titleAlignment;
      if (ltr) {
        if (lastButton != null) {
          maxX = lastButton.getX() - titleSpacing;
        } else {
          maxX = frame.getWidth() - frame.getInsets().right -
              titleSpacing;
        }
        minX = menuButton.getX() + menuButton.getWidth() +
            titleSpacing;
      } else {
        if (lastButton != null) {
          minX = lastButton.getX() + lastButton.getWidth() +
              titleSpacing;
        } else {
          minX = frame.getInsets().left + titleSpacing;
        }
        maxX = menuButton.getX() - titleSpacing;
        if (titleAlignment == SwingConstants.LEADING) {
          titleAlignment = SwingConstants.TRAILING;
        } else if (titleAlignment == SwingConstants.TRAILING) {
          titleAlignment = SwingConstants.LEADING;
        }
      }
      String clippedTitle = getTitle(title, fm, maxX - minX);
      if (clippedTitle == title) {
        // String fit, align as necessary.
        if (titleAlignment == SwingConstants.TRAILING) {
          minX = maxX - style.getGraphicsUtils(context).
              computeStringWidth(context, g.getFont(), fm, title);
        } else if (titleAlignment == SwingConstants.CENTER) {
          int width = style.getGraphicsUtils(context).
              computeStringWidth(context, g.getFont(), fm, title);
          minX = Math.max(minX, (getWidth() - width) / 2);
          minX = Math.min(maxX - width, minX);
        }
      }
      style.getGraphicsUtils(context).paintText(
          context, g, clippedTitle, minX, baseline - fm.getAscent(), -1);
    }
  }

  public void paintBorder(SynthContext context, Graphics g, int x,
      int y, int w, int h) {
    context.getPainter().paintInternalFrameTitlePaneBorder(context,
        g, x, y, w, h);
  }

  protected LayoutManager createLayout() {
    SynthContext context = getContext(this);
    LayoutManager lm =
        (LayoutManager) style.get(context, "InternalFrameTitlePane.titlePaneLayout");
    context.dispose();
    return (lm != null) ? lm : new SynthTitlePaneLayout();
  }

  public void propertyChange(PropertyChangeEvent evt) {
    if (evt.getSource() == this) {
      if (SynthLookAndFeel.shouldUpdateStyle(evt)) {
        updateStyle(this);
      }
    } else {
      // Changes for the internal frame
      if (evt.getPropertyName() == JInternalFrame.FRAME_ICON_PROPERTY) {
        updateMenuIcon();
      }
    }
  }

  /**
   * Resets the menuButton icon to match that of the frame.
   */
  private void updateMenuIcon() {
    Icon frameIcon = frame.getFrameIcon();
    SynthContext context = getContext(this);
    if (frameIcon != null) {
      Dimension maxSize = (Dimension) context.getStyle().get(context,
          "InternalFrameTitlePane.maxFrameIconSize");
      int maxWidth = 16;
      int maxHeight = 16;
      if (maxSize != null) {
        maxWidth = maxSize.width;
        maxHeight = maxSize.height;
      }
      if ((frameIcon.getIconWidth() > maxWidth ||
          frameIcon.getIconHeight() > maxHeight) &&
          (frameIcon instanceof ImageIcon)) {
        frameIcon = new ImageIcon(((ImageIcon) frameIcon).
            getImage().getScaledInstance(maxWidth, maxHeight,
            Image.SCALE_SMOOTH));
      }
    }
    context.dispose();
    menuButton.setIcon(frameIcon);
  }


  class SynthTitlePaneLayout implements LayoutManager {

    public void addLayoutComponent(String name, Component c) {
    }

    public void removeLayoutComponent(Component c) {
    }

    public Dimension preferredLayoutSize(Container c) {
      return minimumLayoutSize(c);
    }

    public Dimension minimumLayoutSize(Container c) {
      SynthContext context = getContext(
          SynthInternalFrameTitlePane.this);
      int width = 0;
      int height = 0;

      int buttonCount = 0;
      Dimension pref;

      if (frame.isClosable()) {
        pref = closeButton.getPreferredSize();
        width += pref.width;
        height = Math.max(pref.height, height);
        buttonCount++;
      }
      if (frame.isMaximizable()) {
        pref = maxButton.getPreferredSize();
        width += pref.width;
        height = Math.max(pref.height, height);
        buttonCount++;
      }
      if (frame.isIconifiable()) {
        pref = iconButton.getPreferredSize();
        width += pref.width;
        height = Math.max(pref.height, height);
        buttonCount++;
      }
      pref = menuButton.getPreferredSize();
      width += pref.width;
      height = Math.max(pref.height, height);

      width += Math.max(0, (buttonCount - 1) * buttonSpacing);

      FontMetrics fm = SynthInternalFrameTitlePane.this.getFontMetrics(
          getFont());
      SynthGraphicsUtils graphicsUtils = context.getStyle().
          getGraphicsUtils(context);
      String frameTitle = frame.getTitle();
      int title_w = frameTitle != null ? graphicsUtils.
          computeStringWidth(context, fm.getFont(),
              fm, frameTitle) : 0;
      int title_length = frameTitle != null ? frameTitle.length() : 0;

      // Leave room for three characters in the title.
      if (title_length > 3) {
        int subtitle_w = graphicsUtils.computeStringWidth(context,
            fm.getFont(), fm, frameTitle.substring(0, 3) + "...");
        width += (title_w < subtitle_w) ? title_w : subtitle_w;
      } else {
        width += title_w;
      }

      height = Math.max(fm.getHeight() + 2, height);

      width += titleSpacing + titleSpacing;

      Insets insets = getInsets();
      height += insets.top + insets.bottom;
      width += insets.left + insets.right;
      context.dispose();
      return new Dimension(width, height);
    }

    private int center(Component c, Insets insets, int x,
        boolean trailing) {
      Dimension pref = c.getPreferredSize();
      if (trailing) {
        x -= pref.width;
      }
      c.setBounds(x, insets.top +
          (getHeight() - insets.top - insets.bottom -
              pref.height) / 2, pref.width, pref.height);
      if (pref.width > 0) {
        if (trailing) {
          return x - buttonSpacing;
        }
        return x + pref.width + buttonSpacing;
      }
      return x;
    }

    public void layoutContainer(Container c) {
      Insets insets = c.getInsets();
      Dimension pref;

      if (SynthLookAndFeel.isLeftToRight(frame)) {
        center(menuButton, insets, insets.left, false);
        int x = getWidth() - insets.right;
        if (frame.isClosable()) {
          x = center(closeButton, insets, x, true);
        }
        if (frame.isMaximizable()) {
          x = center(maxButton, insets, x, true);
        }
        if (frame.isIconifiable()) {
          x = center(iconButton, insets, x, true);
        }
      } else {
        center(menuButton, insets, getWidth() - insets.right,
            true);
        int x = insets.left;
        if (frame.isClosable()) {
          x = center(closeButton, insets, x, false);
        }
        if (frame.isMaximizable()) {
          x = center(maxButton, insets, x, false);
        }
        if (frame.isIconifiable()) {
          x = center(iconButton, insets, x, false);
        }
      }
    }
  }

  private JButton createNoFocusButton() {
    JButton button = new JButton();
    button.setFocusable(false);
    button.setMargin(new Insets(0, 0, 0, 0));
    return button;
  }
}
